/*
 * UserDAO.java
 *
 * Created on June 16, 2007, 7:39 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package jhub.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import jhub.Hub;
import jhub.UserSession;
import jhub.management.UserManager;
import jhub.management.exception.UserNotFoundException;
import jhub.users.Admin;
import jhub.users.Operator;
import jhub.users.Registered;
import jhub.users.User;
import jhub.users.VIP;

/**
 *
 * @author dbotelho
 */
public class UserDAO extends AbstractDAO {
    
    private final PreparedStatement selectAllUsersStatement;
    private final PreparedStatement getUserByNickStatement;
    private final PreparedStatement getUserByNickHubStatement;
    private final PreparedStatement getUserStatement;
    private final PreparedStatement getUserPasswdStatement;
    private final PreparedStatement addUserStatement;
    private final PreparedStatement addRegisteredStatement;
    private final PreparedStatement addOperatorStatement;
    private final PreparedStatement addVipStatement;
    private final PreparedStatement addAdminStatement;
    
    private int getNextKey() throws SQLException{
        return super.nextValue("user_id_seq");
    }
    
    /** Creates a new instance of UserDAO */
    public UserDAO(Connection conn) throws SQLException {
        super(conn);
        this.selectAllUsersStatement = conn.prepareStatement("SELECT * FROM \"user\"");
        this.getUserByNickStatement = conn.prepareStatement("SELECT * FROM \"user\" WHERE nick = ?");
        this.getUserByNickHubStatement = conn.prepareStatement("SELECT * FROM \"user\" WHERE nick = ? AND hub_id = ?");
        this.getUserStatement = conn.prepareStatement("SELECT * FROM \"user\" WHERE user_id = ? AND hub_id=?");
        this.getUserPasswdStatement = conn.prepareStatement("SELECT * FROM \"registered\" WHERE user_id = ?");
        this.addUserStatement = conn.prepareStatement("INSERT INTO \"user\" (id,hub_id,user_type,nick,description,email,sharesize,speed,version,first_time_seen) VALUES(?,?,?,?,?,?,?,?,?,?)");
        this.addRegisteredStatement = conn.prepareStatement("INSERT INTO \"registered\" (user_id,passwd) VALUES(?,?)");
        this.addOperatorStatement = conn.prepareStatement("INSERT INTO \"operator\" (user_id) VALUES(?)");
        this.addVipStatement = conn.prepareStatement("INSERT INTO \"vip\" (user_id) VALUES(?)");
        this.addAdminStatement = conn.prepareStatement("INSERT INTO \"admin\" (user_id) VALUES(?)");
    }
    
    public void loadUsers(UserManager userManager) throws SQLException{
        ResultSet rs = selectAllUsersStatement.executeQuery();
        while(rs.next()){
            System.out.println("nick: "+rs.getString("nick"));
            System.out.println("email: "+rs.getString("email"));
        }
    }
    
    private User setUser(ResultSet rs) throws SQLException, ClassNotFoundException{
        User user = new User();
        
        
        String user_type = rs.getString("user_type");
        System.out.println(user_type);
        
        if(!UserManager.UserType.valueOf(user_type).equals(UserManager.UserType.user)){
            getUserPasswdStatement.setInt(1,rs.getInt("hub_id"));
                ResultSet rs2 = getUserPasswdStatement.executeQuery();
            if(UserManager.UserType.valueOf(user_type).equals(UserManager.UserType.admin)){
                    
                if(rs2.next()){
                    user = new Admin();
                   ((Admin) user).setPasswd(rs2.getString("passwd"));
                }
            }else if(UserManager.UserType.valueOf(user_type).equals(UserManager.UserType.operator)){
                if(rs2.next()){
                    user = new Operator();
                   ((Operator) user).setPasswd(rs2.getString("passwd"));
                }
            }else if(UserManager.UserType.valueOf(user_type).equals(UserManager.UserType.vip)){
                if(rs2.next()){
                    user = new VIP();
                   ((VIP) user).setPasswd(rs2.getString("passwd"));
                }
            }else{
                if(rs2.next()){
                    user = new Registered();
                   ((Registered) user).setPasswd(rs2.getString("passwd"));
                }
            }
        }
        
        user.setHub(DAOFactory.getHubDAO().getHubByID(rs.getInt("hub_id")));
        user.setId(rs.getInt("id"));
        user.setNick(rs.getString("nick"));
        user.setDescription(rs.getString("description"));
        user.setEmail(rs.getString("email"));
        user.setSharesize(rs.getLong("sharesize"));
        user.setSpeed(rs.getString("speed"));
        user.setVersion(rs.getString("version"));
        
        return user;
    }
    
    /*public User findUserByNick(String nick) throws SQLException, ClassNotFoundException{
        User user = null;
        getUserByNickStatement.setString(1,nick);
        ResultSet rs = getUserByNickStatement.executeQuery();
        if(rs.next()){
            
            user = setUser(rs);
        }
        return user;
    }
    
    public boolean containsUserByNick(String nick) throws SQLException{
        getUserByNickStatement.setString(1,nick);
        ResultSet rs = getUserByNickStatement.executeQuery();
        return rs.next();
    }*/
    
    public boolean contains(User user) throws SQLException, ClassNotFoundException{
        try {
            findByExample(user);
            return true;
        } catch (UserNotFoundException ex) {
            return false;
        }
        
    }
    
    public User findByExample(User user) throws SQLException, UserNotFoundException, ClassNotFoundException{
        if(user.getHub()!=null){
            if(user.getNick()!=null){
                getUserByNickHubStatement.setString(1,user.getNick());
                getUserByNickHubStatement.setInt(2,user.getHub().getId());
                ResultSet rs = getUserByNickHubStatement.executeQuery();
                if(rs.next()){
                    user = setUser(rs);
                    return user;
                }
               
            }
        }
            
        throw new UserNotFoundException();
    }
    
    public void save(User user) throws SQLException{
        UserManager.UserType user_type;
        
        
        if(user instanceof Admin)
            user_type = UserManager.UserType.admin;
        else if(user instanceof Operator)
            user_type = UserManager.UserType.operator;
        else if(user instanceof VIP)
            user_type = UserManager.UserType.vip;
        else if(user instanceof Registered)
            user_type = UserManager.UserType.registered;
        else
            user_type = UserManager.UserType.user;
        
        conn.setAutoCommit(false);
        try{
            saveUser(user,user_type);
            
            if(user_type.equals(UserManager.UserType.admin)){
                saveRegistered((Registered) user);
                saveOperator((Operator) user);
                saveAdmin((Admin) user);
            }else if(user_type.equals(UserManager.UserType.operator)){
                saveRegistered((Registered) user);
                saveOperator((Operator) user);
            }else if(user_type.equals(UserManager.UserType.vip)){
                saveRegistered((Registered) user);
                saveVip((VIP) user);
            }else if(user_type.equals(UserManager.UserType.registered)){
                saveRegistered((Registered) user);
            }
            
            conn.commit();
        }catch(SQLException ex){
            ex.printStackTrace();
            conn.rollback();
        }
        conn.setAutoCommit(true);
        
    }
    
    private void saveAdmin(Admin admin) throws SQLException{
        addAdminStatement.setInt(1,admin.getId());
        addAdminStatement.executeUpdate();
    }
    
    private void saveVip(VIP vip) throws SQLException{
        addVipStatement.setInt(1,vip.getId());
        addVipStatement.executeUpdate();
    }
    
    private void saveRegistered(Registered reg) throws SQLException{
        addRegisteredStatement.setInt(1,reg.getId());
        addRegisteredStatement.setString(2,reg.getPasswd());
        addRegisteredStatement.executeUpdate();
    }
    
    private void saveOperator(Operator op) throws SQLException{
        addOperatorStatement.setString(1,op.getNick());
        addOperatorStatement.executeUpdate();
    }
    
    private void saveUser(User user,UserManager.UserType user_type) throws SQLException{
        int i=1;
        user.setId(this.getNextKey());
        addUserStatement.setInt(i++,user.getId());
        addUserStatement.setInt(i++,user.getHub().getId());
        addUserStatement.setString(i++,user_type.toString());
        addUserStatement.setString(i++,user.getNick());
        addUserStatement.setString(i++,user.getDescription());
        addUserStatement.setString(i++,user.getEmail());
        addUserStatement.setLong(i++,(user.getSharesize()!=null)?user.getSharesize():new Long(0));
        addUserStatement.setString(i++,user.getSpeed());
        addUserStatement.setString(i++,user.getVersion());
        addUserStatement.setLong(i++,user.getFirstTimeSeen().getTime());
        
        addUserStatement.executeUpdate();
    }

    
    
}
